package com.yuanda.erp9.syn.util;

import com.yuanda.erp9.syn.contant.DateConstants;
import com.yuanda.erp9.syn.exception.TargetServerException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/**
 * @author linuo
 * @desc 文件工具类
 * @time 2022年12月7日15:38:39
 */
public class FileUtils {
    private static final Logger log = LoggerFactory.getLogger(FileUtils.class);


    /**
     * 从网络Url中下载文件
     *
     * @param urlStr
     * @param fileName
     * @param savePath
     * @throws IOException
     */
    public static String downLoadFromUrl(String urlStr, String fileName, String savePath) {
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置超时间为3秒
            conn.setConnectTimeout(3 * 1000);
            // 防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

            // 得到输入流
            InputStream inputStream = conn.getInputStream();
            // 获取字节数组
            byte[] getData = readInputStream(inputStream);

            // 文件保存位置
            Map<String, Integer> yearMonthDay = DateUtils.getYearMonthDay();
            Integer year = yearMonthDay.get(DateConstants.YEAR);
            Integer month = yearMonthDay.get(DateConstants.MONTH);
            Integer day = yearMonthDay.get(DateConstants.DAY);
            savePath = savePath + year + File.separator + month + File.separator + day + File.separator;
            File saveDir = new File(savePath);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }

            File file = new File(saveDir + File.separator + fileName);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(getData);
            fos.close();
            inputStream.close();
            return saveDir + File.separator + fileName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 从输入流中获取字节数组
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    /**
     * 远程文件下载地址 并解压
     *
     * @param urlStr 网络文件请求地址
     */
    public static String DownAndReadFileAndUnZipFiles(String urlStr, String savePath, Integer supplierId) {
        long startTime = System.currentTimeMillis();
        // 声明文件对象
        File saverPath = new File(savePath);
        // 判断文件是否存在
        if (!saverPath.exists()) {
            // 文件不存在就创建一个一级目录【远程请求下载】
            saverPath.mkdir();
        }
        // 根据/切割接受到的请求网络URL
        String[] urlName = urlStr.split("/");
        // 获取到切割的字符串数组长度-1
        int len = urlName.length - 1;
        // 获取到请求下载文件的名称
        String uname = urlName[len];

        // 跳过try捕获错误
        try {
            // 创建保存文件对象
            File file = new File(saverPath + "/" + uname);//创建新文件
            if (file != null && !file.exists()) {
                file.createNewFile();
            }
            // 通过高效字节输出流输出创建的文件对象
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
            // 创建URL对象[请求路径]
            URL url = new URL(urlStr);
            // 返回一个URLConnection实例，表示与URL引用的远程对象的URL
            HttpURLConnection uc = (HttpURLConnection) url.openConnection();
            // 设置的值 doInput领域本 URLConnection指定值。
            uc.setDoInput(true);
            // 打开与此URL引用的资源的通信链接，如果此类连接尚未建立。
            uc.connect();
            // 获取服务端的字节输入流
            InputStream inputStream = uc.getInputStream();
            // 声明字节数组存放读取的文件
            byte[] b = new byte[1024 * 4];
            int byteRead = -1; // 定义读取次数
            // 循环读取
            while ((byteRead = inputStream.read(b)) != -1) {
                // 将读取的文件跳过高效的字节流输出
                bufferedOutputStream.write(b, 0, byteRead);
            }
            // 关闭流和刷新流
            inputStream.close();
            bufferedOutputStream.close();
            long endTime = System.currentTimeMillis();
            System.out.println("下载耗时：" + (endTime - startTime) / 1000 * 1.0 + "s");
            System.out.println("文件下载成功！");
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("文件下载失败 ",e);
            throw new TargetServerException("下载异常：" + e, supplierId, urlStr);
        }
        try {
            System.out.println("解压文件中...");
            return unZipFiles(savePath + uname, savePath);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("文件解压失败 ",e);
            throw new TargetServerException("解压异常：" + e, supplierId, urlStr);
        }
    }

    /**
     * 解压的文件
     *
     * @param zipPath 压缩文件
     * @param descDir 解压存放的位置
     * @throws Exception
     */
    public static String unZipFiles(String zipPath, String descDir) throws Exception {
        System.out.println("解压文件的名称：" + zipPath + " 解压的文件存放路径：" + descDir);
        // 调用方法
        return zipDecompressing(zipPath, descDir);
    }

    /**
     * 解压文件到指定的位置
     *
     * @param zipFile 解压文件
     * @param descDir 存放目录
     */
    public static String unZipFiles(File zipFile, String descDir) throws Exception {
        // 创存放文件的对象
        File pathFile = new File(descDir);
        // 判断文件是否存在
        if (!pathFile.exists()) {
            // 创建目录[不找到压缩文件里的内容，所以需要创建多级目录]
            pathFile.mkdirs();
        }
        // 创建压缩包条目
        ZipFile zip = new ZipFile(zipFile, Charset.forName("gbk"));
        String filePath = "";
        // entries() 打开一个ZIP文件，读取指定的File对象。
        for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
            ZipEntry entry = (ZipEntry) entries.nextElement(); // 获取条目
            String zipEntryMame = entry.getName(); // 获取条目名
            InputStream in = zip.getInputStream(entry); // 获取文件的输入流
            String outPath = (descDir + zipEntryMame).replaceAll("\\*", "//"); // 替换全部
            // 判断路径是否存在
            File file = new File(outPath.substring(0, outPath.lastIndexOf("\\")));
            // 判断文件，不存在就创建
            if (!file.exists()) {
                file.mkdirs(); // 多级目录
            }
            // 判断文件路径是否为文件
            if (new File(outPath).isDirectory()) {
                continue;
            }
            // 创建字节输出流
            FileOutputStream out = new FileOutputStream(outPath);
            // 创建字节数组
            byte[] byf1 = new byte[1024];
            int len;
            while ((len = in.read(byf1)) != -1) {
                out.write(byf1);
            }
            // 关闭流
            in.close();
            out.close();
            filePath = outPath;
        }
        System.out.println("文件解压成功,filePath:" + filePath);
        return filePath;
    }

    /**
     * 解压
     *
     * @param directory
     * @param localPath
     * @return
     * @throws Exception
     */
    public static String zipDecompressing(String directory, String localPath) throws Exception {
        //输入源zip路径
        ZipInputStream Zin = new ZipInputStream(new FileInputStream(
                directory), Charset.forName("gbk"));
        BufferedInputStream Bin = new BufferedInputStream(Zin);
        try {
            //输出路径（文件夹目录）
            String parent = localPath;
            File fout = null;
            ZipEntry entry;
            String filePath = "";
            while ((entry = Zin.getNextEntry()) != null && !entry.isDirectory()) {
                fout = new File(parent, entry.getName());
                if (!fout.exists()) {
                    (new File(fout.getParent())).mkdirs();
                }
                FileOutputStream out = new FileOutputStream(fout);
                BufferedOutputStream Bout = new BufferedOutputStream(out);
                int b;
                while ((b = Bin.read()) != -1) {
                    Bout.write(b);
                }
                Bout.close();
                out.close();
                filePath = parent + entry.getName();
                System.out.println("文件解压成功,filePath:" + filePath);
            }
            return filePath;
        } finally {
            Bin.close();
            Zin.close();
        }
    }

    /**
     * avnet下载
     *
     * @param userName  登陆用户
     * @param password  登陆密码
     * @param loginUrl  登陆地址
     * @param downUrl   下载地址
     * @param saverPath 保存地址
     * @param allicUrl  下载内容 allic.csv  allic_asia.csv allic_emea.csv
     */
    public static String avnetDownAndReadFile(String userName, String password, String loginUrl, String downUrl, String saverPath, String allicUrl, Integer supplierId) {
        try {
            // 登陆地址
            HttpPost post = new HttpPost(loginUrl);
            // 登陆参数
            List<NameValuePair> parameters = new ArrayList<NameValuePair>();
            parameters.add(new BasicNameValuePair("username", userName));
            parameters.add(new BasicNameValuePair("password", password));
            parameters.add(new BasicNameValuePair("command", "login"));
            parameters.add(new BasicNameValuePair("skip_login", "true"));
            parameters.add(new BasicNameValuePair("encoded", "true"));
            parameters.add(new BasicNameValuePair("random", ""));
            UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, HTTP.UTF_8);
            post.setEntity(sendentity);
            // 创建 client
            HttpClient client = new DefaultHttpClient();
            HttpResponse postResponse = client.execute(post);
            EntityUtils.consume(postResponse.getEntity());
            String path = avnetDown(client, new HttpGet(downUrl + allicUrl), saverPath);
            client.getConnectionManager().shutdown();
            return path;
        } catch (Exception e) {
            log.info("下载错误,e", e);
            throw new TargetServerException("下载异常：" + e, supplierId, downUrl + allicUrl);
        }
    }


    public static String avnetDown(HttpClient client, HttpGet httpget, String saverPath) throws Exception {
        long startTime = System.currentTimeMillis();
        BufferedOutputStream bufferedOutputStream = null;
        InputStream inputStream = null;
        try {
            //Execute get
            HttpContext context = new BasicHttpContext();
            HttpResponse getResponse = client.execute(httpget, context);
            if (getResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                log.info("文件地址错误,");
                throw new IOException(getResponse.getStatusLine().toString());
            }
            HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
            String currentUrl = URLDecoder.decode(currentReq.getURI().toString(), "UTF-8");

            int i = currentUrl.lastIndexOf('/');
            String fileName = null;
            if (i < 0) {
                fileName = currentUrl;
            } else {
                fileName = currentUrl.substring(i + 1);
            }
            String filePath = saverPath + fileName;
            // 创建保存文件对象
            File file = new File(filePath);//创建新文件
            if (file != null && !file.exists()) {
                file.createNewFile();
            }
            // 通过高效字节输出流输出创建的文件对象
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));

            inputStream = getResponse.getEntity().getContent();
            // 声明字节数组存放读取的文件
            byte[] b = new byte[1024 * 4];
            int byteRead = -1; // 定义读取次数
            // 循环读取
            while ((byteRead = inputStream.read(b)) != -1) {
                // 将读取的文件跳过高效的字节流输出
                bufferedOutputStream.write(b, 0, byteRead);
            }

            long endTime = System.currentTimeMillis();
            System.out.println("下载耗时：" + (endTime - startTime) / 1000 * 1.0 + "s");
            return filePath;
        } finally {
            // 关闭流和刷新流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}